/*
 * Copyright © 2024-2025 Wenze Wei
 *
 * This file is part of StadionOS.
 *
 * This Source Code Form is subject to the terms of the GNU General Public License, v. 2.0.
 * You can obtain a copy of the GPL at
 * https://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 */

#include "animation.h"
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

uint32_t animation_get_time() {
    struct timespec ts;
    timespec_get(&ts, 0);
    return (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
}

void animation_init(WindowAnimation* anim, float duration_ms, EaseType ease_type) {
    anim->start_time = (int32_t)(animation_get_time());
    if (duration_ms <= 0) {
        duration_ms = 1000.0f;
    }
    if (ease_type < EASE_LINEAR || ease_type > EASE_IN_OUT_QUAD) {
        ease_type = EASE_LINEAR;
    }
    anim->duration = duration_ms;
    anim->ease_type = ease_type;
}

int animation_update(WindowAnimation* anim) {
    float current = animation_get_time();
    float elapsed = current - (float)anim->start_time;
    float progress = elapsed / anim->duration;
    
    if (progress >= 1.0f) {
        return 1;
    }
    
    progress = animation_calculate_ease(anim->ease_type, progress);
    
    if (anim->update_callback) {
        struct {
            float m[4][4];
        } current_matrix;
        glUseProgram(anim->shader_program);
        glUniformMatrix4fv(anim->matrix_uniform, 1, GL_FALSE, (GLfloat*)&anim->transform_matrix);
        glUniform1f(anim->progress_uniform, progress);
        
        return anim->update_callback(anim->user_data, 
            anim->start_x + (anim->target_x - anim->start_x) * progress,
            anim->start_y + (anim->target_y - anim->start_y) * progress,
            anim->start_width + (anim->target_width - anim->start_width) * progress,
            anim->start_height + (anim->target_height - anim->start_height) * progress,
            &current_matrix);
    }
    return 0;
}

float animation_calculate_ease(EaseType type, float progress) {
    switch(type) {
        case EASE_LINEAR:
            return progress;
        case EASE_OUT_QUAD:
            return 1.0f - (1.0f - progress) * (1.0f - progress);
        case EASE_IN_OUT_CUBIC:
            return progress < 0.5f ? 4 * progress * progress * progress : 1 - pow(-2 * progress + 2, 3) / 2;
        default:
            return progress;
    }
}
